import { defineComponent, ref, computed, watchEffect, provide, createVNode } from 'vue';
import { Value } from '../../inner/Value.js';
import Dropdown from '../../Dropdown/index.js';
import { Menu } from './Menu.js';
import { CascaderStore } from './store.js';
import { Option } from './Option.js';
import Empty from '../../Empty/index.js';

const CascaderContextKey = Symbol('CascaderContextKey');
const index = /* @__PURE__ */ defineComponent({
  name: 'Cascader',
  props: {
    disabled: {
      type: Boolean
    },
    clearable: {
      type: Boolean
    },
    size: {
      type: String
    },
    prepend: {
      type: [String, Object]
    },
    modelValue: {
      type: [String, Array]
    },
    valueField: {
      type: String
    },
    titleField: {
      type: String
    },
    mode: {
      type: String
    },
    showMax: {
      type: Number
    },
    max: {
      type: Number
    },
    showMore: {
      type: Boolean
    },
    filter: {
      type: Boolean
    },
    emptyText: {
      type: String
    },
    seperator: {
      type: String
    },
    transfer: {
      type: Boolean,
      default: true
    },
    header: {
      type: Object
    },
    footer: {
      type: Object
    },
    triggerRender: {
      type: Function
    },
    align: {
      type: String
    },
    revers: {
      type: Boolean,
      default: true
    },
    data: {
      type: Array
    },
    trigger: {
      type: String
    },
    multi: {
      type: Boolean
    },
    tagRender: {
      type: Function
    },
    changeOnSelect: {
      type: Boolean
    },
    placeholder: {
      type: String
    },
    beforeChecked: {
      type: Function
    },
    loadData: {
      type: Function
    },
    asFormField: {
      type: Boolean,
      default: true
    }
  },
  emits: ['change', 'exceed', 'update:modelValue', 'select'],
  setup(props, {
    emit
  }) {
    const store = new CascaderStore(props, emit);
    const visible = ref(false);
    const query = ref('');
    const trigger = props.trigger ?? 'click';
    const emptyText = props.emptyText ?? '暂无数据';
    const filterWrap = ref();
    const allTextNodes = [];
    const titleField = props.titleField ?? 'title';
    const seperator = props.seperator ?? '/';
    const align = props.align ?? 'bottomLeft';
    const classList = computed(() => ({
      'cm-cascader': true,
      'cm-cascader-disabled': props.disabled,
      'cm-cascader-clearable': !props.disabled && props.clearable && store.value.value && store.value.value.length,
      [`cm-cascader-${props.size}`]: props.size
    }));
    const text = computed(() => {
      const vals = store.value.value;
      const newVals = vals?.filter(val => store.store.nodeMap[val]);
      const arr = newVals ? newVals.map(val => {
        const item = store.store.nodeMap[val];
        return props.multi ? item : item[titleField];
      }) : [];
      return props.multi ? arr : arr.length ? arr.join(seperator) : '';
    });
    const onSelect = item => {
      // 点击的是叶子节点或者设置点击即改变
      if (!props.multi) {
        if (!(item.children && item.children.length) || props.changeOnSelect) {
          emit('select', item);
          const vals = store.selectedKey.value;
          const rets = [...vals];
          store.value.value = rets;
          if (props.filter) {
            query.value = '';
          }
          emit('change', rets);
        }
      }
      // 点击叶子节点进行关闭
      if (!(item.children && item.children.length) && !props.multi) {
        visible.value = false;
      }
    };
    const onClear = () => {
      store.value.value = [];
      emit('change', []);
    };

    // 过滤查询
    watchEffect(() => {
      const queryStr = query.value;
      if (queryStr) {
        store.filter(queryStr);

        // 高亮搜索字符
        queueMicrotask(() => {
          buildNodes();
          hilightKeyword(queryStr);
        });
      }
    });

    // 高亮关键字
    const hilightKeyword = queryStr => {
      // 不支持高亮则返回
      if (!CSS.highlights) {
        return;
      }
      CSS.highlights.delete('cm-search-results');
      const str = queryStr.trim().toLowerCase();
      if (!str) {
        return;
      }
      const ranges = allTextNodes.map(el => {
        return {
          el,
          text: el.textContent?.toLowerCase()
        };
      }).map(({
        text,
        el
      }) => {
        const indices = [];
        let startPos = 0;
        while (text && startPos < text.length) {
          const index = text.indexOf(str, startPos);
          if (index === -1) break;
          indices.push(index);
          startPos = index + str.length;
        }
        return indices.map(index => {
          const range = new Range();
          range.setStart(el, index);
          range.setEnd(el, index + str.length);
          return range;
        });
      });
      const searchResultsHighlight = new Highlight(...ranges.flat());
      CSS.highlights.set('cm-search-results', searchResultsHighlight);
    };

    // 撤消按键，删除最后一个value
    const onDeleteLastValue = () => {
      if (props.multi) {
        const val = store.value.value;
        if (val.length > 0) {
          const key = val.pop();
          store.checkNode(key, false);
        }
      }
    };
    const clearQuery = () => {
      query.value = '';
    };

    /**
    * 构建搜索的节点
    * @returns
    */
    const buildNodes = () => {
      // 不支持高亮则返回
      if (!CSS.highlights) {
        return;
      }
      const treeWalker = document.createTreeWalker(filterWrap.value, NodeFilter.SHOW_TEXT);
      let currentNode = treeWalker.nextNode();
      while (currentNode) {
        allTextNodes.push(currentNode);
        currentNode = treeWalker.nextNode();
      }
    };
    provide(CascaderContextKey, {
      onSelect,
      loadData: props.loadData,
      multi: props.multi,
      clearQuery
    });
    return () => createVNode("div", {
      "class": classList.value,
      "tab-index": "0"
    }, [createVNode(Dropdown, {
      "modelValue": visible.value,
      "onUpdate:modelValue": $event => visible.value = $event,
      "transfer": props.transfer,
      "align": align,
      "revers": props.revers,
      "trigger": "click",
      "disabled": props.disabled,
      "menu": createVNode("div", {
        "class": "cm-cascader-dropdown"
      }, [props.header ?? null, query.value ? createVNode("div", {
        "class": "cm-cascader-wrap",
        "ref": filterWrap
      }, [createVNode("div", {
        "class": {
          'cm-cascader-list': true,
          'cm-cascader-list-empty': !store.store.filteredList?.length
        }
      }, [store.store.filteredList?.length ? store.store.filteredList.map(item => {
        return createVNode(Option, {
          "filter": props.filter,
          "store": store,
          "data": item,
          "seperator": seperator
        }, null);
      }) : createVNode("div", {
        "class": "cm-cascader-empty"
      }, [createVNode(Empty, {
        "width": 100,
        "text": emptyText
      }, null)])])]) : createVNode("div", {
        "class": "cm-cascader-wrap"
      }, [store.store.columns.map((column, index) => {
        return createVNode(Menu, {
          "key": store.selectedKey.value[index - 1] || 'root',
          "data": column,
          "trigger": trigger,
          "store": store,
          "emptyText": props.emptyText
        }, null);
      })]), props.footer ?? null])
    }, {
      default: () => [props.triggerRender ? createVNode("span", {
        "class": "cm-cascader-trigger"
      }, [props.triggerRender?.(text.value, store.value.value)]) : createVNode(Value, {
        "prepend": props.prepend,
        "text": text.value,
        "showMore": props.showMore,
        "showMax": props.showMax,
        "onClear": onClear,
        "clearable": props.clearable,
        "placeholder": props.placeholder,
        "disabled": props.disabled,
        "size": props.size,
        "multi": props.multi,
        "query": query,
        "filter": props.filter,
        "onDeleteLastValue": onDeleteLastValue,
        "tagRender": props.tagRender
      }, null)]
    })]);
  }
});

export { CascaderContextKey, index as default };
